package org.cjava.system.dao.util;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import org.hibernate.Criteria;

import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Disjunction;
import org.hibernate.transform.Transformers;
import org.springframework.transaction.annotation.Transactional;

@Transactional(readOnly = true)
public class GenericEntityDao<T, ID extends Serializable> implements
        IGenericEntityDao<T, ID> {

    protected SessionFactory sessionFactory;
    private final Class<T> oClass;

    public GenericEntityDao() {
        this.oClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];

    }

    @Override
    public Class<T> getObjectClass() {
        return this.oClass;
    }

    @Transactional(readOnly = false, rollbackFor=Exception.class)
    @Override
    public int save(T objeto) throws Exception {
        return (Integer) getSessionFactory().getCurrentSession().save(objeto);
    }

    @Transactional(readOnly = false)
    @Override
    public void update(T objeto) throws Exception {
        getSessionFactory().getCurrentSession().update(objeto);
    }

    @Transactional(readOnly = false)
    @Override
    public void saveOrUpdate(T object) throws Exception {
        getSessionFactory().getCurrentSession().saveOrUpdate(object);
    }

    @Transactional(readOnly = false)
    @Override
    public void delete(T objeto) throws Exception {
        getSessionFactory().getCurrentSession().delete(objeto);
    }

    @Transactional(readOnly = false)
    @Override
    public int HQLexecute(String hql) throws Exception {
        Integer rowsAffected = getSessionFactory().getCurrentSession()
                .createQuery(hql)
                .executeUpdate();
        return rowsAffected;
    }

    @Transactional(readOnly = false)
    @Override
    public int SQLexecute(String SQL) throws Exception {
        Integer rowsAffected = getSessionFactory().getCurrentSession()
                .createSQLQuery(SQL)
                .executeUpdate();
        return rowsAffected;
    }

    @Override
    public T getById(Serializable id) throws Exception {
        T object = (T) getSessionFactory()
                .getCurrentSession().get(oClass, id);
        return object;
    }

    @Override
    public T getByHQL(String HQL) throws Exception {
        T object = (T) getSessionFactory()
                .getCurrentSession()
                .createQuery(HQL)
                .uniqueResult();
        return object;
    }
    
    @Override
    public List list() throws Exception {
        List list = getSessionFactory().getCurrentSession()
                .createCriteria(oClass).list();
        return list;
    }

    @Override
    public List listHQL(String hql, Class clazz) throws Exception {
        List list = getSessionFactory().getCurrentSession()
                .createQuery(hql)
                .setResultTransformer(Transformers.aliasToBean(clazz))
                .list();
        return list;
    }

    @Override
    public List listHQL(String hql) throws Exception {
        List list = getSessionFactory().getCurrentSession()
                .createQuery(hql)
                .list();
        return list;
    }

    @Override
    public List listHQL(String hql, int lazyChargeOption, Object object) throws Exception {
        List list = getSessionFactory().getCurrentSession()
                .createQuery(hql)
                .list();
        return list;
    }
    
    @Override
    public List listHQL(String HQL, int firstResult, int maxResult) throws Exception {
        List list = getSessionFactory().getCurrentSession().createQuery(HQL)
                .setFirstResult(firstResult)
                .setMaxResults(maxResult)
                .list();
        return list;
    }

    @Override
    public List listCriterion(List<Criterion> listCriterion) throws Exception{
        Criteria criteria = getSessionFactory().getCurrentSession()
                .createCriteria(oClass);
        for (int i = 0; i < listCriterion.size(); i++) {
            criteria.add(listCriterion.get(i));
        }
        return criteria.list();
    }
    
    @Override
    public List listCriterion(List<Criterion> listCriterion, String[]alias, Disjunction disjunction) throws Exception{
        
        Criteria criteria = getSessionFactory().getCurrentSession()
                .createCriteria(oClass);
        for (int i = 0; i < listCriterion.size(); i++) {
            criteria.add(listCriterion.get(i));
        }
        for (int i = 0; i < alias.length; i++) {
            String []al = alias[i].split(",");
            criteria.createAlias(al[0], al[1]);            
        }
        criteria.add(disjunction);
        return criteria.list();
    }

    public SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    @Override
    public List listSQL(String SQL) throws Exception {
        List list = getSessionFactory().getCurrentSession()
                .createSQLQuery(SQL)
                .setResultTransformer(Transformers.aliasToBean(oClass))
                .list();
        return list;
    }
    
}
